package com.yifeng.repo.base.utils.common;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.RateLimiter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * Created by daibing on 2021/8/25.
 */
@SuppressWarnings("UnstableApiUsage")
public class FireLimiter {
    private static final Logger LOGGER = LoggerFactory.getLogger(FireLimiter.class);
    private static final Cache<String, RateLimiter> CACHE = CacheBuilder.newBuilder()
            .initialCapacity(32).expireAfterAccess(1, TimeUnit.MINUTES).build();
    /**
     * qps
     */
    private final double limit;

    public FireLimiter(double limit) {
        this.limit = limit;
    }

    public boolean isLimit(String accessKey) {
        try {
            RateLimiter limiter = CACHE.get(accessKey, new Callable<RateLimiter>() {
                @Override
                public RateLimiter call() throws Exception {
                    return RateLimiter.create(limit);
                }
            });
            // 可以在timeout过期之前获取到许可就返回true，否则立即返回false（无需等待）
            if (!limiter.tryAcquire(1000, TimeUnit.MILLISECONDS)) {
                LOGGER.error("access_key: {} limited", accessKey);
                return true;
            }
        } catch (ExecutionException e) {
            LOGGER.error("create limit fail: accessKey={}, error=", accessKey, e);
        }
        return false;
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("fire limiter start to do...");
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
        FireLimiter fireLimiter = new FireLimiter(10);
        for (int i = 0; i < 100; i++) {
            System.out.println(String.format("%3d %s limit: %s", i, sdf.format(new Date()), fireLimiter.isLimit("9999999")));
            if (i % 15 == 3) {
                System.out.print("sleep start...");
                Thread.sleep(300);
                System.out.println("sleep end...");
            }
        }
    }
}
